package com.linjacy.httpproject.aspect;

import com.alibaba.fastjson.JSON;
import com.linjacy.httpproject.component.ApplicationRunnerComponent;
import com.linjacy.httpproject.component.LogQueueTaskHandler;
import com.linjacy.httpproject.entity.SysLog;
import com.linjacy.httpproject.mapper.SysLogMapper;
import com.linjacy.httpproject.response.R;
import com.linjacy.httpproject.service.SysLogService;
import com.mysql.cj.util.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
@Aspect
public class LogAspect {

    private static Logger log = LoggerFactory.getLogger(LogAspect.class);

    @Autowired
    SysLogMapper sysLogMapper;

    @Autowired
    LogQueueTaskHandler logQueueTaskHandler;

    @Pointcut(value = "@annotation(com.linjacy.httpproject.annotation.NeedToLog)")
    public void logPointCut(){}

    @Around("logPointCut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Object proceed = null;
        String result = "";
        String errorMsg = "";
        //记录执行前的时间
        long startTime = System.currentTimeMillis();
        //获取方法参数
        Object[] args = joinPoint.getArgs();
        //获取参数名
        String[] parameterNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames();
        Map<String, Object> paramMap = new HashMap<>();
        for (int i = 0; i < parameterNames.length; i++) {
            if("token".equals(parameterNames[i])) continue;
            paramMap.put(parameterNames[i], args[i]);
        }
        try{
            proceed = joinPoint.proceed();
            result = JSON.toJSONString(proceed);
        }catch (Exception e){
            result = getExceptionMessage(e);
            errorMsg = e.getMessage();
        }
        long endTime = System.currentTimeMillis();
        logQueueTaskHandler.setBaseParamAndAddLogTask(JSON.toJSONString(paramMap), result, ((Long)(endTime - startTime)).toString());
        return proceed == null? (StringUtils.isNullOrEmpty(errorMsg) ? R.error("系统异常") : R.error(errorMsg)) : proceed;
    }


    @Before("logPointCut()")
    public void doBefore(JoinPoint joinPoint) {
        // 接收到请求，记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;
        HttpServletRequest request = attributes.getRequest();
        // 获取入参
        Object[] args = joinPoint.getArgs();
        String params=null;
        if(args.length!=0){
            params= JSON.toJSONString(args);
        }
        // 记录下请求内容
        log.info("==========> 前端请求, 请求路径:{}, 请求方法:{},  IP地址:{}, 类方法:{}, 参数:{}",
                request.getRequestURL().toString(), request.getMethod(),
                request.getRemoteAddr(), joinPoint.getSignature().getDeclaringTypeName() + "." +
                        joinPoint.getSignature().getName(),
                JSON.toJSONString(params));
    }



    private static String getExceptionMessage(Exception e){
        try {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            try {
                e.printStackTrace(pw);
                return sw.toString();
                } finally {
                    pw.close();
                }
            }catch (Exception e1){

            }
        return null;
    }

}
